package com.winit.openapi.interceptor;

import java.math.BigDecimal;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.fastjson.JSONObject;
import com.winit.common.spi.context.CommandContext;
import com.winit.openapi.constants.ApiConstant;
import com.winit.openapi.constants.ErrorCode;
import com.winit.openapi.model.RequestMsg;
import com.winit.openapi.model.ResponseMsg;
import com.winit.openapi.util.RequestUtil;
import com.winit.tracing.client.Tracer;

/**
 * 日志拦截器
 * 
 * @version Revision History
 * 
 * <pre>
 * Author     Version       Date        Changes
 * kang.wang    1.0           2014-10-24     Created
 * 
 * </pre>
 * @since 1.
 */
public class LogInterceptor implements HandlerInterceptor {

    private static final Logger logger       = LoggerFactory.getLogger(LogInterceptor.class);

    private static final String BLANK_WHITE  = "|";

    /**
     * 过滤带有密码参数的请求键值
     */
    private static final String PASSWORD_REG = "[\\w]*[pP][ass]{3}[wW][ord]{3}[\\w]*";

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object obj,
                                Exception exception) throws Exception {
        try {
            RequestMsg requestMsg = RequestUtil.getRequestMsg(request);
            ResponseMsg responseMsg = RequestUtil.getResponseMsg(request);
            // 记录输入输出日志
            doLog(request, requestMsg, responseMsg);

            String errorCode = responseMsg.getCode();
            String action = requestMsg.getAction();
            CommandContext ctx = CommandContext.getContext();
            Object seq = ctx.get(ApiConstant.API_REQUEST_SEQ);
            if (seq == null) {
                seq = System.nanoTime();
            }
            // 过滤掉tracking.getOrderTracking接口。原因：有爬虫调用，导致这个接口日志量暴增，暂时屏蔽
            if (!ErrorCode.SUCCESS.equals(errorCode) && !"tracking.getOrderTracking".equals(action)) {
                String sourceInputStr = (String) request.getAttribute(ApiConstant.SOURCE_INPUT_STRING);
                Tracer.addData("errorDesc", responseMsg.getMsg());
                Tracer.addData("requestBody",
                    StringUtils.isBlank(sourceInputStr) ? JSONObject.toJSONString(requestMsg) : sourceInputStr);
                Tracer.addData("errorCode", errorCode);
                Tracer.addData("sequence", seq);
                // 非系统错误的抛出错误码代表的信息标识错误信息，系统错误的要给出具体堆栈信息
                if (!ErrorCode.SYSTEM_ERROR.equals(errorCode)) {
                    Tracer.setException(new RuntimeException(errorCode));
                }
            }
            long timeStart = Long.parseLong(seq.toString());
            long timeEnd = System.nanoTime();
            BigDecimal timeCost = (BigDecimal.valueOf(timeEnd).subtract(BigDecimal.valueOf(timeStart))).divide(BigDecimal.valueOf(1000 * 1000 * 1000),
                3,
                BigDecimal.ROUND_DOWN);
            logger.info("Seq:" + timeStart + BLANK_WHITE + "User:" + requestMsg.getApp_key() + BLANK_WHITE + "API:"
                        + requestMsg.getAction() + BLANK_WHITE + "end.." + BLANK_WHITE + "耗时：" + timeCost.doubleValue()
                        + " 秒");

        } finally {

            Tracer.complete();
            // 销毁session
            HttpSession session = request.getSession();
            session.invalidate();
            session = null;
        }

    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object obj,
                           ModelAndView modelandview) throws Exception {

    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object obj) throws Exception {
        return true;
    }

    /**
     * 记录日志
     * 
     * @param requestMsg
     * @param responseMsg
     */
    private void doLog(HttpServletRequest request, RequestMsg requestMsg, ResponseMsg responseMsg) {
        if (requestMsg == null) {
            return;
        }

        // 打印发票，不记录日志
        if (requestMsg.getAction().equals("winitLable.query") || requestMsg.getAction().equals("winitInvoice.query")) {
            responseMsg.setData(StringUtils.EMPTY);
        }
        // 不打印密码
        String sourceInputStr = (String) request.getAttribute(ApiConstant.SOURCE_INPUT_STRING);

        // 替换入参出参中的敏感信息比如密码，token等
        sourceInputStr = replace(PASSWORD_REG, sourceInputStr, requestMsg.getData().toString());
        //屏蔽获取Token接口
        if(requestMsg.getAction().contains("getToken")){
            responseMsg.setData(StringUtils.EMPTY);
        }
        String app_key = requestMsg.getApp_key();
        if (app_key == null) {
            JSONObject json = JSONObject.parseObject(requestMsg.getData().toString());
            if (json.containsKey("userName")) {
                app_key = json.getString("userName");
            }
        }

        String inputJsonStr = JSONObject.toJSONString(requestMsg);
        String outputJsonStr = JSONObject.toJSONString(responseMsg);

        String action = request.getRequestURI();
        int index = action.indexOf("/", 1);
        if (index != -1) {
            action = action.substring(index);
        }
        // 添加API调用序列,API调用频率
        CommandContext ctx = CommandContext.getContext();
        Object seq = ctx.get(ApiConstant.API_REQUEST_SEQ);
        Object frequency = ctx.get(ApiConstant.API_FREQUENCY_PER_UNIT);

        StringBuffer buf = new StringBuffer();
        if (seq != null) {
            buf.append("Seq:" + seq.toString()).append("|");
        }
        if (frequency != null) {
            buf.append("frequency:" + frequency.toString()).append("|");
        }
        buf.append(app_key).append("|");
        buf.append(action).append("|");
        buf.append(RequestUtil.getIp(request)).append("|");
        if (StringUtils.isNotBlank(sourceInputStr)) {
            buf.append(sourceInputStr).append("||");
        } else {
            buf.append(inputJsonStr).append("|");
        }
        buf.append(outputJsonStr);

        logger.info(buf.toString());
    }

    private String replace(String reg, String sourceStr, String dataStr) {
        Pattern pattern = Pattern.compile(reg);
        String key = null;
        String value = null;
        try {
            if (StringUtils.isNotBlank(sourceStr)) {
                Matcher matcher = pattern.matcher(sourceStr);
                if (matcher.find()) {
                    key = matcher.group(0);
                    JSONObject json = JSONObject.parseObject(dataStr);
                    if (json.containsKey(key)) {
                        value = (String) json.get(key);
                        if (StringUtils.isNotBlank(value)) {
                            String sourceInputStr = sourceStr.replaceAll(value, StringUtils.EMPTY);
                            return sourceInputStr;
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.warn("替换密码属性异常：key" + key);
            return sourceStr;
        }
        return sourceStr;
    }

}
